﻿using System;
using System.Collections.Generic;

namespace Knlght.ObjectFactory
{
    /// <summary>
    /// 对象工厂
    /// </summary>
    public sealed class ObjectFactory
    {
        #region 单例实现
        private static object asyncObj = new object();
        private static ObjectFactory instance = null;
        private ObjectFactory()
        {
            types = new Dictionary<Type, ObjectType>();
            types2 = new Dictionary<Type, ObjectFunc>();
            cacheObjects = new Dictionary<Type, object>();
        }
        private static ObjectFactory current
        {
            get
            {
                if (instance == null)
                {
                    lock (asyncObj)
                    {
                        if (instance == null)
                        {
                            instance = new ObjectFactory();
                        }
                    }
                }
                return instance;
            }
        }
        #endregion
        Dictionary<Type, ObjectType> types = null;          //契约类型与实现类型的字典映射
        Dictionary<Type, ObjectFunc> types2 = null;         //契约类型与通过对象创建方法获取对象的字典映射

        Dictionary<Type, object> cacheObjects = null;       //内存中的缓存对象

        /// <summary>
        /// 类型绑定
        /// </summary>
        /// <param name="contractType">契约类型</param>
        /// <param name="implementType">实现类型</param>
        /// <param name="isSigleton">是否是单例对象</param>
        public static void Bind(Type contractType, Type implementType, bool isSigleton = false)
        {
            if (contractType == null)
            {
                throw new ArgumentNullException("contractType");
            }
            if (implementType == null)
            {
                throw new ArgumentNullException("implementType");
            }

            if (!implementType.IsSubclassOf(contractType))
            {
                throw new ApplicationException($"类型[{implementType}],没有实现接口[{contractType}]");
            }

            lock (asyncObj)
            {
                if (current.types.ContainsKey(contractType))
                {
                    current.types.Remove(contractType);
                }
                current.types.Add(contractType, new ObjectType(implementType, isSigleton));
            }
        }
        /// <summary>
        /// 类型绑定
        /// </summary>
        /// <typeparam name="ContractT">契约类型</typeparam>
        /// <typeparam name="ImplementT">实现类型</typeparam>
        /// <param name="isSingleton">是否是单例对象</param>
        public static void Bind<ContractT, ImplementT>(bool isSingleton = false)
            where ImplementT : ContractT
        {
            Bind(typeof(ContractT), typeof(ImplementT), isSingleton);
        }
        /// <summary>
        /// 类型绑定
        /// </summary>
        /// <typeparam name="ContractT">契约类型</typeparam>
        /// <param name="func">获取指定契约类型的方法</param>
        /// <param name="isSingleton">是否是单例对象</param>
        public static void Bind<ContractT>(Func<object> func, bool isSingleton = false)
        {
            if (func == null)
            {
                throw new ArgumentNullException("func");
            }
            var contractType = typeof(ContractT);
            lock (asyncObj)
            {
                if (current.types.ContainsKey(contractType))
                {
                    current.types.Remove(contractType);
                }
                current.types2.Add(contractType, new ObjectFunc(func, isSingleton));
            }
        }
        /// <summary>
        /// 类型单例绑定
        /// </summary>
        /// <typeparam name="ContractT">契约类型</typeparam>
        /// <param name="func">获取指定契约类型的方法</param>
        public static void BindSingle<ContractT>(Func<object> func)
        {
            Bind<ContractT>(func, true);
        }
        /// <summary>
        /// 获取对象实例
        /// </summary>
        public static T Get<T>() where T : class
        {
            return Get(typeof(T)) as T;
        }
        /// <summary>
        /// 获取对象实例
        /// </summary>
        public static object Get(Type contractType)
        {
            if (contractType == null)
            {
                throw new ArgumentNullException("contractType");
            }

            if (current.cacheObjects.ContainsKey(contractType))
            {
                return current.cacheObjects[contractType];
            }

            if (current.types2.ContainsKey(contractType))     //先从高性能字典中查找对象构造方法，如果存在，则直接创建对象
            {
                var tmp = current.types2[contractType];
                var obj = tmp.Func();
                if (tmp.IsSingleton)
                {
                    current.cacheObjects.Add(contractType, obj);
                }
                return obj;
            }

            if (current.types.ContainsKey(contractType))
            {
                var tmp = current.types[contractType];
                var obj = Activator.CreateInstance(tmp.ImplementType);
                if (tmp.IsSingleton)
                {
                    current.cacheObjects.Add(contractType, obj);
                }
                return obj;
            }

            throw new ApplicationException($"无法找到类型[{contractType}]的注册!");
        }

    }
}
